package project.innovation.mooddiagnosis.controller;

import com.fasterxml.jackson.core.JsonProcessingException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import project.innovation.mooddiagnosis.entity.file.ChunkInfo;
import project.innovation.mooddiagnosis.entity.file.FileInfo;
import project.innovation.mooddiagnosis.entity.result.Result;
import project.innovation.mooddiagnosis.entity.user.UserInfo;
import project.innovation.mooddiagnosis.service.ChunkService;
import project.innovation.mooddiagnosis.service.FileService;
import project.innovation.mooddiagnosis.service.ModelService;
import project.innovation.mooddiagnosis.service.TimetampsService;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.*;

@Slf4j
@RestController
@RequestMapping("/file")
public class FileController {
    @Value("${WindowsFilePath}")
    private String windowsFilePath;
    @Value("${LINUXFilePath}")
    private String linuxFilePath;
    @Value("${LINUX_WINDOWS}")
    private boolean linuxWindows;

    @Autowired
    private FileService fileService;
    @Autowired
    private ChunkService chunkService;
    @Autowired
    private ModelService modelService;
    @Autowired
    private TimetampsService timetampsService;

    SimpleDateFormat formatter= new SimpleDateFormat("yyyy-MM-dd 'at' HH:mm:ss z");

    private static final Logger logger = LoggerFactory.getLogger(FileController.class);

    /**
     * 通过md5查找数据库中是否有对应文件信息 如果有 说明该视频已经上传
     * @param md5 文件md5码
     * @return 是否有对应文件
     */
    @GetMapping("/check")
    public Result checkFile(@RequestParam("md5") String md5) {
        logger.info("checkFile");
        Boolean isUpload = fileService.selectFileByMd5(md5);
        Map<String , Object> data = new HashMap<>();
        data.put("isUpload", isUpload);
        if (isUpload){
            return new Result(201, "文件已秒传", data);
        }

        //如果没有，就查找分片信息，并返回给前端
        List<ChunkInfo> chunkList = chunkService.selectChunkListByMd5(md5);
        data.put("chunkList",chunkList);

        return  new Result(201,"",data);
    }

    /**
     * 检测和上传文件的接口 通过isupload区分是否带时间戳（isupload == 0 说明是检测）
     * @param chunk                 文件
     * @param md5                   文件md5码
     * @param index                 分片编号
     * @param isend                 是否是最后一个分片
     * @param fileName              文件名
     * @param chunkSize             分片大小
     * @param userInfoJsonString    用户信息
     * @param timetamps_string      时间戳信息（这里用的是string类型）
     * @param isupload              是否是在线检测
     * @return 检测结果 Result(201, "分片上传成功", index);or Result(200, "文件上传成功", index); （当前文件分片的index）
     * @throws Exception
     */
    @PostMapping("/upload/chunk")
    public Result uploadChunk(@RequestParam("chunk") MultipartFile chunk,
                              @RequestParam("md5") String md5,
                              @RequestParam("index") Integer index,
                              @RequestParam("isend") Integer isend,
                              @RequestParam("fileName")String fileName,
                              @RequestParam("chunkSize")Long chunkSize,
                              @RequestParam("userInfo") String userInfoJsonString,
                              @RequestParam("timetamps") String timetamps_string,
                              @RequestParam("isupload") Integer isupload
    ) throws Exception {
        UserInfo userInfo = UserInfo.fromJsonString(userInfoJsonString);
        String [] splits = fileName.split("\\.");
        String type = splits[splits.length-1];

        String resultFileName_without_path        = md5 + "." + type;
        String chunkFileName_without_path         = md5 + "_" + index + "." + type;
        String chunkFileName_changed_without_path = md5 + "_" + index + "_changed" + "." + type;
        String resultFileName;
        String chunkFileName;
        String chunkFileName_changed;
        if(linuxWindows){
            resultFileName =  linuxFilePath + resultFileName_without_path;
            chunkFileName =  linuxFilePath + chunkFileName_without_path;
            chunkFileName_changed =  linuxFilePath + chunkFileName_changed_without_path;
        } else {
            resultFileName =  windowsFilePath + resultFileName_without_path;
            chunkFileName =  windowsFilePath + chunkFileName_without_path;
            chunkFileName_changed =  windowsFilePath + chunkFileName_changed_without_path;
        }

        logger.info("resultFileName in uploadChunk:{}", resultFileName);
        chunkService.saveChunk(chunk, md5, index, chunkSize, chunkFileName, chunkFileName_changed);

        if(isend == 1){
            logger.info("fileName in fileInfo: {}", fileName);
            FileInfo fileInfo = new FileInfo(fileName, md5);
            fileService.addFile(fileInfo);
            //问答（有时间戳）
            if(isupload == 0)
            {//保存现在的time
                double [] timetamps = handleTimetamps(timetamps_string);
                String timetampsName = "video_timetamps"+md5 + ".json";
                timetampsService.saveTimetamps(timetamps, timetampsName);
                logger.info("begin to run model. Q&A");
                modelService.moodDiagnosis(userInfo, md5, resultFileName_without_path, timetampsName, resultFileName, index);
            }
            else {
                logger.info("begin to run model. File");
                modelService.moodDiagnosis(userInfo, md5, resultFileName_without_path, resultFileName, index);
            }

            return new Result(200, "文件上传成功", index);
        } else {
            return new Result(201, "分片上传成功", index);
        }
    }

    @GetMapping("/fileList")
    public Result getFileList(){
        logger.info("getFileList");
        List<FileInfo> fileInfoList = fileService.selectFileList();
        return  new Result(200,"文件列表查询成功",fileInfoList);
    }

    /**
     * 下载文件接口
     * @param filename 需要下载的文件名
     * @param response 返回数据？
     * @throws IOException
     */
    @GetMapping("/download")
    public void downloadFile(String filename, HttpServletResponse response) throws IOException {
        logger.info("downloadFile");
        response.reset();
        // 从文件读到servlet response输出流中
        String filePath = "/home/app/ppt/" + filename;
        logger.info("filePath:{}", filePath);
        File file = new File(filePath);
        if(!file.exists()){
            response.setStatus(HttpServletResponse.SC_NOT_FOUND);
            response.setContentType("application/json");
            response.getWriter().write("{\"error\":\"file not exists\",\"filename\":\""+filename+"\"}");
            return;
        }
        response.setContentType("application/octet-stream");
        response.setHeader("Content-disposition", "attachment;filename=" + filename);
        try (FileInputStream inputStream = new FileInputStream(file);) { // try-with-resources
            byte[] b = new byte[1024];
            int len;
            while ((len = inputStream.read(b)) > 0) {
                response.getOutputStream().write(b, 0, len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private double[] handleTimetamps(String timetamps_string){
        logger.info("timetamps_string: {}", timetamps_string);
        timetamps_string = timetamps_string.substring(1, timetamps_string.length()-1);
        String[] timetamps = timetamps_string.split(",");
        double[] timetampsDouble = new double[timetamps.length];
        for (int i = 0; i < timetamps.length; i++) {
            timetampsDouble[i] = Double.parseDouble(timetamps[i]);
        }
        return timetampsDouble;
    }
}